<?php

	define('ROUTER_EVT_INITIALIZE',	'ROUTER_EVT_INITIALIZE');
	define('ROUTER_EVT_RESOLVE_ROUTE',	'ROUTER_EVT_RESOLVE_ROUTE');

	$n2f = n2f_cls::getInstance();
	$n2f->registerExtension(
	    'router',
	    'Router for N2F',
	    '0.2',
	    'Chris Butcher',
	    'http://www.cbutcher.org'
	);

	/*
	 * Example of routing structure
	 *
	 * 	$routes = array(
	 * 		'calendar' => array(
	 * 			'view' => array(
	 * 				'params' => array('nmod', 'page', 'month', 'day'),
	 * 				'defaults' => array(
	 * 					'nmod' => 'calendar',
	 * 					'page' => 'view'
	 * 				)
	 * 			)
	 * 		),
	 *
	 * 		'store' => array(
	 * 			'params' => array('nmod' => 'store'),
	 * 			'default' => array()
	 * 		)
	 * 	);
	 *
	 * 	Perhaps we should exchange the path
	 *
	 * 		( /calendar/view/{month}/{day} )
	 *
	 * 			with regex
	 *
	 *   	( /calendar/view/(\w+)/(\w+) )
	 */

	class router extends n2f_events {

		/**
		 * Regex values that will replace the the slugs
		 * in the route pattern.
		 *
		 * @var array
		 */
		protected static $_regex = array(
			'any'	=> '[A-Za-z0-9_-\W]+',
			'int' 	=> '[0-9]+',
			'string' 	=> '[A-Za-z0-9_-]+',
			'hex'	=> '[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}'
		);

		/**
		 * List of all the routes.
		 *
		 * @var array
		 */
		protected static $_routes = array();

		/**
		 * Initialize a new instance of the router.
		 */
		public function __construct()
		{
			$this->addEvent(ROUTER_EVT_INITIALIZE, true);
			$this->addEvent(ROUTER_EVT_RESOLVE_ROUTE, true);

			$this->hookEvent(ROUTER_EVT_INITIALIZE, array(&$this, '_init'));
			$this->hookEvent(ROUTER_EVT_RESOLVE_ROUTE, array(&$this, '_resolve'));
		}

		/**
		 * Adds a route to the list of available routes.
		 *
		 * @param string  $path
		 * @param array   $defaults
		 */
		public static function addRoute($path, array $defaults = array())
		{
			if (!isset(router::$_routes[$path]) || !is_array(router::$_routes[$path])) {
				router::$_routes[$path] = $defaults;
			}
		}

		/**
		 * Add multiple routes to the list of available routes.
		 *
		 * @param array $routes
		 */
		public static function addRoutes(array $routes = array())
		{
			if (count($routes) > 0) {
				foreach ($routes as $path => $defaults) {
					router::addRoute($path, $defaults);
				}
			}
		}

		/**
		 * The initialize event is responsible for parsing the route information
		 * into parameters.
		 */
		public function initialize()
		{
			if (isset($this->events[ROUTER_EVT_INITIALIZE]) && is_array($this->events[ROUTER_EVT_INITIALIZE])) {
				$routes = $this->hitEvent(ROUTER_EVT_INITIALIZE, array(router::$_routes));
				if (is_array($routes) && count($routes) > 0) {
					router::$_routes = $routes;
				}
			} else {
				$n2f = n2f_cls::getInstance();
				if($n2f->debug->showLevel(N2F_DEBUG_ERROR)) {
					$n2f->debug->throwError(0, 'Initialization method for router does not exist.', 'router.ext.php');
				}
			}
		}

		/**
		 * The resolve event is responsible for matching the requested URI and
		 * then assigned the parameter values.
		 */
		public function resolve()
		{
			if (isset($this->events[ROUTER_EVT_RESOLVE_ROUTE]) && is_array($this->events[ROUTER_EVT_RESOLVE_ROUTE])) {
				$this->hitEvent(ROUTER_EVT_RESOLVE_ROUTE, array(router::$_routes));
			} else {
				$n2f = n2f_cls::getInstance();
				if($n2f->debug->showLevel(N2F_DEBUG_ERROR)) {
					$n2f->debug->throwError(0, 'Resolve method for router does not exist.', 'router.ext.php');
				}
			}
		}

		/**
		 * The default initialization method, which can be overridden by hooking a
		 * new initialization method onto the ROUTER_EVT_INITIALIZE event.
		 *
		 * @param array $routes
		 *
		 * @return array
		 */
		public function _init(array $routes = array())
		{
			if (count($routes) < 1) {
				return $routes;
			}

			$route  = array();
			$parsed = array();

			foreach ($routes as $fullPath => $defaults) {
				$path 	= '';
				$params 	= array();

				if (preg_match_all('#{(.*?)}#', $fullPath, $params) > 0) {
					foreach (array_values($params[1]) as $param) {
						$path = str_replace("/{{$param}}", '', $fullPath);
					}
				}

				$path = trim($path, '/');
				if ($path == '') {
					$path = '/';
				}

				$parsed[$path] = array(
					'path'		=> $path,
					'params' 		=> $params[1],
					'defaults' 	=> $defaults
				);
			}

			return $parsed;
		}

		/**
		 * The default resolution method, which can be overridden by hooking an
		 * event on the the ROUTER_EVT_RESOLVE_ROUTE event.
		 *
		 * @param array $routes
		 *
		 * @return bool
		 */
		public function _resolve(array $routes = array())
		{
			if (!isset($_REQUEST['_route'])) {
				return false;
			}

			$route 	 = array();
			$requested = $_REQUEST['_route'];

			if (count($routes) > 0) {
				foreach ($routes as $route) {
					if (strpos($requested, $route['path']) == 0) {
						break;
					}
				}
			}

			if (isset($route['params']) && is_array($route['params'])) {

			}

			return true;
		}
	}

	// Since we don't want to override parts of the n2f core functionality,
	// we are just going to execute the routes upon loading the router extension.

	if ($n2f->requireExtensions(array('router/routes'))) {
		$router = new router();
		$router->initialize();
		$router->resolve();
	}

?>